import { Component, OnInit, OnDestroy, HostBinding } from '@angular/core';
import { fuiMessageService } from 'flash-ui';
import { Subscription } from 'rxjs';

import COLOR_PROPERTIES from '../__auto__/color-properties';
import COLOR_VARIABLES from '../__auto__/color-variables';
import { CopierService } from '../shared/copier/copier.service';

import { StyleManagerService } from '../shared/style-manager';

@Component({
  selector: 'fui-color',
  templateUrl: './color.component.html',
  styleUrls: ['./color.component.sass'],
})
export class ColorComponent implements OnInit, OnDestroy {
  @HostBinding('class') hostClass = 'fui-layout2-content';

  colorVariables: any[] = COLOR_VARIABLES;

  colorProperties: any[] = COLOR_PROPERTIES;

  filteredColorVariables: any[] = [];

  filteredColorProperties: any[] = [];

  suggestColorVariables: any[] = [];

  suggestColorProperties: any[] = [];

  suggestNumber = 5;

  searchFilter: string;

  themeKeySub: Subscription;

  constructor(
    private message: fuiMessageService,
    private styleManager: StyleManagerService,
    private copier: CopierService,
  ) { }

  ngOnInit() {
    this.initColorValues();
    this.getFilteredColors();
    this.addThemeKeyListener();
  }

  ngOnDestroy() {
    this.removeThemeKeyListener();
  }

  initColorValues() {
    this.colorProperties.forEach((property) => {
      property.value = this.getColorValue(property.name);
    });

    this.colorVariables.forEach((variable) => {
      variable.value = this.getColorValue(variable.property);
    });
  }

  getColorValue(property: string) {
    return getComputedStyle(document.documentElement).getPropertyValue(property).trim();
  }

  getFilteredColors() {
    this.filteredColorProperties = this.colorProperties.slice();
    this.filteredColorVariables = this.colorVariables.slice();

    if (this.searchFilter) {
      this.filteredColorProperties = this.filteredColorProperties.filter((property) =>
        property.name.toLowerCase().indexOf(this.searchFilter.toLowerCase()) > -1 ||
        property.value.toLowerCase().indexOf(this.searchFilter.toLowerCase()) > -1);

      this.filteredColorVariables = this.filteredColorVariables.filter((variable) =>
        variable.name.toLowerCase().indexOf(this.searchFilter.toLowerCase()) > -1 ||
        variable.value.toLowerCase().indexOf(this.searchFilter.toLowerCase()) > -1 ||
        variable.property.toLowerCase().indexOf(this.searchFilter.toLowerCase()) > -1);
    }
  }

  getSuggestColors() {
    this.suggestColorProperties = [];
    this.suggestColorVariables = [];

    if (/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/.test(this.searchFilter)) {
      this.suggestColorProperties = this.colorProperties.slice().sort((a, b) =>
        this.getColorDistance(this.searchFilter, a.value) - this.getColorDistance(this.searchFilter, b.value)).slice(0, this.suggestNumber);
      this.suggestColorVariables = this.colorVariables.slice().sort((a, b) =>
        this.getColorDistance(this.searchFilter, a.value) - this.getColorDistance(this.searchFilter, b.value)).slice(0, this.suggestNumber);
    }
  }

  copyName(name: string) {
    if (this.copier.copyText(name)) {
      this.message.success('Name copied');
    } else {
      this.message.error('Copy failed. Please try again!');
    }
  }

  addThemeKeyListener() {
    this.themeKeySub = this.styleManager.themeKeyObservable
    .subscribe(() => {
      setTimeout(() => {
        this.initColorValues();
        this.onSearch();
      }, 500);
    });
  }

  removeThemeKeyListener() {
    if (this.themeKeySub) {
      this.themeKeySub.unsubscribe();
    }
  }

  onSearch() {
    if (this.searchFilter) {
      this.searchFilter = this.searchFilter.trim();
    }
    this.getFilteredColors();
    this.getSuggestColors();
  }

  /**
   * Calculate color distance
   *
   * @param colorA Hex color #AAAAAA
   * @param colorB Hex color #BBBBBB
   */
  private getColorDistance(colorA, colorB) {
    const colorAValue = this.hexToRGB(colorA);
    const colorBValue = this.hexToRGB(colorB);

    const distance = Math.sqrt(Math.pow(colorAValue.red - colorBValue.red, 2) +
      Math.pow(colorAValue.green - colorBValue.green, 2) + Math.pow(colorAValue.blue - colorBValue.blue, 2));

    return distance;
  }

  private hexToRGB(hex: string) {
    if (/^#[a-fA-F0-9]{6}$/.test(hex)) {
      return {
        red: parseInt(hex.substr(1, 2), 16),
        green: parseInt(hex.substr(3, 2), 16),
        blue: parseInt(hex.substr(5, 2), 16),
      };
    } else if (/^#[a-fA-F0-9]{3}$/.test(hex)) {
      return {
        red: parseInt(hex.substr(1, 1) + hex.substr(1, 1), 16),
        green: parseInt(hex.substr(2, 1) + hex.substr(2, 1), 16),
        blue: parseInt(hex.substr(3, 1) + hex.substr(3, 1), 16),
      };
    }
  }
}
